package com.pi.shisan.component.impl;

import com.pi.shisan.common.NumberUtil;
import com.pi.shisan.common.TextPxCreater;
import com.pi.shisan.component.AnimationComponent;
import com.pi.shisan.component.util.AnimationThread;
import com.pi.shisan.component.util.ComponentThread;
import com.pi.shisan.component.util.FastIntList;
import com.pi.shisan.util.spipoint.DataWriter;
import com.pi.shisan.util.spipoint.MultipleXyToSpiConverter;

import java.util.Objects;

/**
 * 滚动文字组件
 */
public class ScrollTextComponent extends AnimationComponent {


    public ScrollTextComponent(MultipleXyToSpiConverter spi, DataWriter dataWriter) {
        super(spi,dataWriter);
    }

    /**
     * 上一次绘制过的所有点保存
     */
    private final FastIntList lastAllPoints = new FastIntList();

    /**
     * 组件内容坐标X
     */
    private int fromX;
    /**
     * 组件内容坐标Y
     */
    private int fromY;

    private String text;

    @Override
    protected AnimationThread prepareAnimation() {
        return new ScrollTextAnimationThread(this);
    }

    @Override
    public void refresh() {
        ComponentThread.execute(()->{
            lastAllPoints.forEach(spi::put);
            flushData();
        });
    }

    public void setText (String text) {
        if (Objects.equals(this.text, text)) {
            return;
        }
        this.text = text;
        if (animationThread == null) {
            start();
            waitStart();
        }
        ComponentThread.execute(()->{
            int[] allPoints = TextPxCreater.getAllPointsSameLine(text, 14);
            if (animationThread != null) {
                ((ScrollTextAnimationThread)animationThread).setCachedPoints(allPoints);
            }
        });
    }

    public String getText() {
        return text;
    }

    private int refresh(int fromX, int[] points) {
        lastAllPoints.forEach(spi::delete);
        //修复这个家伙可能带来的内存溢出问题（之前都没做过clear...）
        lastAllPoints.clear();
        final int startX = this.startX;
        final int startY = this.startY;
        final int width = this.width;
        final int height = this.height;
        int boundX = width > 0 ? startX + width : -1;
        int boundY = height > 0 ? startY + height : -1;
        int maxX = Integer.MIN_VALUE;
        for (int i = 0; i < points.length; i++) {
            int x = NumberUtil.toX(points[i]);
            int y = NumberUtil.toY(points[i]);
            x = x+startX+fromX;
            y = y + startY;
            maxX = Math.max(maxX,x);
            if (x < startX || y < startY || (boundX > -1 && x >= boundX) || (boundY > -1 && y >= boundY)) {
                continue;
            }
            spi.put(x,y);
            lastAllPoints.add(NumberUtil.toXy((short) x, (short) y));
        }
        flushData();
        return maxX >= 0 ? fromX - 1 : startX + width;
    }

    static class ScrollTextAnimationThread extends AnimationThread {

        private ScrollTextComponent scrollTextComponent;

        private int[] cachedPoints;

        private int fromX = 0;

        public ScrollTextAnimationThread(ScrollTextComponent scrollTextComponent) {
            this.scrollTextComponent = scrollTextComponent;
            setName("scroll-text-animation");
        }

        @Override
        public void doRun() {
            while (!destroy) {
                final int points[] = this.cachedPoints;
                if (points == null) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                    }
                    continue;
                }
                ComponentThread.execute(()->{
                    final int fromX = this.fromX;
                    int update = scrollTextComponent.refresh(fromX, points);
                    if (points == cachedPoints) {
                        this.fromX = update;
                    }
                });
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
            }
        }

        public void setCachedPoints(int[] cachedPoints) {
            this.cachedPoints = cachedPoints;
            interrupt();
        }
    }
}
